home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Tools&Utilities / EnterAct Stuff / Minimal App7 ƒ / minimalApp7.c < prev    next >
C/C++ Source or Header  |  1996-08-29  |  27KB  |  999 lines

  1. /* minimalApp7.c - a do-nothing-but-call Drag_on Modules  application.  by
  2. Ken Earle, 1989/91/92/93. Copyright? Shirley you must be joking.
  3.  
  4. To see the hilites of calling Drag_on Modules, search this file for *****
  5.  
  6. NOTE System 7 is required  to  run  Minimal  App7.  Future  releases  will
  7. incorporate ever more System 7 features.
  8.  
  9. ThinkC project "MinimalApp7.π" outline:
  10. (NOTE May 96 we have switched to CodeWarrior and the project is now call
  11. "MinimalApp7.µ", but the setup is essentially the same as below.)
  12.  
  13.     Options...; <MacHeaders>, Check Pointers, Require Protoypes
  14.     Set Project Type...; File Type APPL, Creator ???? or whatever
  15.     Size Flags:
  16.  
  17.                                                 √MultiFinder-Aware
  18.                                                 √Background Null Events
  19.                                                 √Suspend & Resume Events
  20.  
  21.  
  22.  
  23.                                                  Background Only
  24.                                                  Get FrontClicks
  25.                                                  Accept ChildDiedEvents
  26.  
  27.  
  28.                                                 √32-Bit Compatible
  29.                                                 √HighLevelEvent-Aware
  30.                                                  Accept Remote HighLevelEvents
  31.                                                  Stationery-Aware
  32.                                                  Use TextEdit Services
  33.  
  34.  
  35.  
  36.     Files:
  37.         minimalApp7.c    - in the “Minimal App7 ƒ” folder
  38.         Call_Resource.c - also in the “Minimal App7 ƒ” folder (a copy of
  39.             the other Call_Resource.c file in “code to call Drag_ons”,
  40.             slightly modified for use with Minimal App7)
  41.     Headers: <MacHeaders> <string.h>
  42.     Libs: MacTraps, ANSI (the ordinary one, not ANSI a4 etc)
  43.     Resources: MinimalApp7.π.rsrc (just a SICN) in the “Minimal App7 ƒ” folder
  44.  
  45. NOTE place the built Minimal App7 in  the  same  folder  as  the  “Drag_on
  46. Modules” folder, at the same level. Typically this will be where EnterAct is.
  47.  
  48. You should see hAWK and Read Resource under the Edit menu  when  you  fire
  49. this up. Options for input will be limited to “Specific file”  with  hAWK,
  50. and neither module will be able to tell this little  application  to  show
  51. you the results of a run - you’ll have to use  a  real  editor  for  that.
  52. Other than that, everything will happen as though you were  calling  these
  53. from EnterAct or some other real application.
  54.  
  55. Once you’re familiar with hAWK, it’s easy to modify a program to take  its
  56. input from a list of files in some specific  file.  For  details  see  the
  57. "hAWK User’s Manual", in the "Other ways of specifying input"  section  of
  58. the "Advanced topics" chapter. For an easy way to run a hAWK program  from
  59. Minimal App7 using  a  list  of  files,  see  the  supplied  hAWK  program
  60. "$MA7_RunClip". Note though that "$MA7_RunClip" works properly only if the
  61. actual program being run does not use preset variables, or if it is OK for
  62. all preset variables to be null.
  63.  
  64. Minimal App7 differs from the earlier Minimal App  primarily  in  that  it
  65. will run only under system  7.  It  supports  concurrent  hAWK  execution,
  66. meaning you can start up Minimal App7, start running a hAWK  program,  and
  67. then switch to some other application and continue working.  Minimal  App7
  68. will notify you when the hAWK program is done.
  69.  
  70. Minimal App7 also supports the "getclip()"  function  in  hAWK.  Since  it
  71. doesn't have a private clip, it passes the system  clip.  Note  that  most
  72. applications do not alter the system clip until you switch out.  This  may
  73. change in the future as a result of AppleScript.
  74.  
  75. As of June 96 if MA7 is started with a hAWK command line on the clip  then
  76. MA7 will launch hAWK with the command line (concurrently unless the  shift
  77. or option key is down) and quit when the program is done.  Note  that  MA7
  78. does not support the "MFS" (multi-file selection) input option, so  either
  79. specific input files or no input files at all  should  be  passed  in  the
  80. command line. Since the scrap is used  for  the  command  line,  the  hAWK
  81. program should not be expecting to find input via getclip() either.
  82. */
  83.  
  84. #include <AppleEvents.h>
  85.  
  86. #include <Traps.h>
  87. #include <GestaltEqu.h>
  88.  
  89. /*
  90.  * Some useful macros
  91.  */
  92. #define alpha(c)    (('a'<=(c)&&(c)<='z')||('A'<=(c)&&(c)<='Z')||(c)=='_')
  93. #define num(c)        ('0'<=(c) && (c)<='9')
  94. #define alphanum(c)    (alpha(c)||num(c))
  95.  
  96. /* Some useful key constants
  97. */
  98. #define        CR                0x0D        /* return                */
  99. #define        BLANK            ' '         /* a space */
  100. #define        OPTBL            ' '            /* option-space */
  101.  
  102. /* kOSEvent is the event number of the suspend/resume and mouse-moved events sent
  103.    by MultiFinder. Once we determine that an event is an OSEvent, we look at the
  104.    high byte of the message sent to determine which kind it is. To differentiate
  105.    suspend and resume events we check the resumeMask bit. */
  106. #define    kOSEvent                app4Evt    /* event used by MultiFinder */
  107. #define    kSuspendResumeMessage    1        /* high byte of suspend/resume event message */
  108. #define    kResumeMask                1        /* bit of message field for resume vs. suspend */
  109. #define    kMouseMovedMessage        0xFA    /* high byte of mouse-moved event message */
  110.  
  111. /*    kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions. */
  112. #define kExtremeNeg                -32768
  113. #define kExtremePos                (32767 - 1) /* required to address an old region bug */
  114.  
  115. #ifndef _Unimplemented
  116. #define    _Unimplemented 0x9F
  117. #endif
  118. #ifndef _WaitNextEvent
  119. #define _WaitNextEvent 0x60
  120. #endif
  121.  
  122.  
  123. #ifndef NULL
  124. #define NULL        ((void *) 0)
  125. #endif
  126.  
  127. #define        APPLEID                15
  128. #define        FILEID                16
  129. #define        EDITID                17
  130. #define        QUIT                12
  131.  
  132. #define        WindowDataPtr        WindowPtr
  133.  
  134. /* Augmented record of event - see SetEventDetails() */
  135. struct EventDetails
  136.     {
  137.     EventRecord        event;            /* IM 1 pg 249 */
  138.     WindowPtr        mouseDownWindow;/* not necessarily front window */
  139.     Point            localWhere;        /* mousedown point in local coordinates */
  140.     ControlHandle    whichControl;
  141.     short                whatPart;
  142.     Boolean            shiftDown, capsLockDown, optionDown, commandDown, doubleClick;
  143.     };
  144. typedef struct EventDetails EventDetails;
  145.  
  146. /* --------- useful globals ---------------- */
  147. MenuHandle      appleMenu, fileMenu, editMenu;
  148. Boolean            gInBackground, gQuitting;
  149. CursHandle        IBeam, Watch;
  150. EventDetails      gEvtDetails;        /* info about latest event */
  151. Boolean            daInFront;             /* for scrap conversion */
  152. /* cursor management, called by all event loops */
  153. RgnHandle    cursorRgn;
  154. static RgnHandle    arrowRgn;
  155. static RgnHandle    iBeamRgn;
  156. /******* to handle concurrent Drag_on Modules, for version 2 or greater. */
  157. Boolean gNotifying; /* hAWK finished with Minimal App in the background. */
  158. Boolean gHawkIsRunning; /* If true, no quitting and less sleeping. */
  159. NMRec    gNotifyRec;
  160.  
  161. /******* The two functions from elsewhere */
  162. /* Call_Resource.c */
  163. extern void InitCallResources(short vRefNumForApp, 
  164.     char *codeFolderName, short menuID);
  165. /* Note "VERSION2" of CallResource() is being used. */
  166. extern void CallResource
  167.     (short        menuID,
  168.     short        item,
  169.     Boolean        concurrent,        // set FALSE if you don't support concurrent mode
  170.     char        *commandLineP    // -> complete command line or NULL
  171.     );
  172.  
  173. /* Prototypes for functions defined in this file */
  174. short main(void);
  175. void DoStandardInits(void);
  176. void MakeMenus(void);
  177. Boolean DoMenu(long);
  178. /* Apple event handlers */
  179. pascal OSErr Handle_aevt_oapp(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon);
  180. pascal OSErr Handle_aevt_odoc(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon);
  181. pascal OSErr Handle_aevt_pdoc(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon);
  182. pascal OSErr Handle_aevt_quit(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon);
  183. OSErr MissedAEKeyword(AppleEvent *theAppleEvent);
  184. /* some WNE functions */
  185. void HandleModelessDialog(void);
  186. void SetEventDetails(void);
  187. unsigned long GetSleep(void);
  188. void BlinkTextCursor(void);
  189. void AdjustCursor(Point mouse, RgnHandle region);
  190. Boolean    IsMultiCursorWindow(WindowDataPtr wdPtr);
  191. void SetWatchCursor(void);
  192. /* support functions */
  193. Boolean System7Available(void);
  194. Boolean TrapAvailable(short theTrap);
  195. TrapType GetTrapType(short theTrap);
  196. short NumToolboxTraps(void);
  197. void AEInstallEventHandlers(void);
  198. void SeeIfDAIsFrontWindow(void);
  199. /********* for concurrent mode Drag_on Module (ie hAWK), handle a single event. */
  200. void HandleOneEvent(void);
  201. // Command line from scrap
  202. Boolean FireOffHawkProgram(void);
  203. char *GetCommandLineFromScrap(void);
  204. Boolean GenericGetName(Ptr *posPtrPtr, Ptr eofPtr, Ptr patPtr, short *patLenP);
  205. void TellHAWKtoQuit(void);
  206.  
  207. /* Init, and the main event loop. Note there is a "one-shot" event loop
  208. at the bottom of this file, called by hAWK during concurrent execution.
  209. */
  210. short main()
  211.     {
  212.     WindowPtr        whichWindow;
  213.     Point            where;
  214.     short            part, appVRefNum;
  215.     Boolean            gotEvent;
  216.     
  217.     DoStandardInits();
  218.     MakeMenus();
  219.     IBeam = GetCursor(iBeamCursor);
  220.     Watch = GetCursor(watchCursor);
  221.     if (!System7Available())
  222.         {
  223.         SysBeep(2);
  224.         SysBeep(0);
  225.         SysBeep(2);
  226.         ExitToShell();
  227.         }
  228.     AEInstallEventHandlers();
  229.     /************* Set up to call Drag_ons */
  230.     if (GetVol(NULL, &appVRefNum))
  231.         appVRefNum = 0;
  232.     InitCallResources(appVRefNum, (Ptr)"\pDrag_on Modules", EDITID);
  233.     
  234.     cursorRgn = NewRgn();        /* we’ll pass WNE an empty region the 1st time thru */
  235.     arrowRgn = NewRgn();
  236.     iBeamRgn = NewRgn();
  237.     
  238.     // June 96, run hAWK if command line is on clip -- we will quit after
  239.     // hAWK program is done in this case
  240.     /************* */
  241.     if (FireOffHawkProgram())
  242.         {
  243.         /****** Remove notice if hAWK finished while Minimal App was
  244.         in the background. Note that at present hAWK will not notify
  245.         us if it is run from a command line (see CallResource()).*/
  246.         if (gNotifying)
  247.             {
  248.             NMRemove(&gNotifyRec);
  249.             if (gNotifyRec.nmIcon)
  250.                 ReleaseResource(gNotifyRec.nmIcon);
  251.             gNotifying = FALSE;
  252.             /* ShowResultsAfterNotify(); -not implemented */
  253.             }
  254.         ExitToShell();
  255.         }
  256.     
  257.     do /* while not quitting */
  258.         {
  259.         SeeIfDAIsFrontWindow();
  260.         if (gInBackground)
  261.             {
  262.             /* handle being in the background */
  263.             ;
  264.             }
  265.         
  266.         gotEvent = WaitNextEvent(everyEvent, &gEvtDetails.event, GetSleep(), cursorRgn);
  267.         if (gotEvent)
  268.             {
  269.             SetEventDetails();
  270.             
  271.             AdjustCursor(gEvtDetails.event.where, cursorRgn);
  272.             
  273.             if (IsDialogEvent(&gEvtDetails.event))
  274.                 HandleModelessDialog(); /* not implemented */
  275.             else
  276.                 {
  277.                 switch (gEvtDetails.event.what)
  278.                     {
  279.                 case mouseDown:
  280.                     switch (part = FindWindow(gEvtDetails.event.where,
  281.                                     &gEvtDetails.mouseDownWindow)) 
  282.                         {
  283.                     case inDesk: 
  284.                         ;
  285.                     break;
  286.                     case inMenuBar:
  287.                         gQuitting = DoMenu(MenuSelect(gEvtDetails.event.where));
  288.                     case inSysWindow:
  289.                         SystemClick (&gEvtDetails.event, gEvtDetails.mouseDownWindow);
  290.                     break;
  291.                     case inDrag:
  292.                     break;
  293.                     case inZoomIn:
  294.                     case inZoomOut:
  295.                     break;
  296.                     case inGrow:
  297.                     break;
  298.                     case inGoAway:
  299.                     break;
  300.                     case inContent:
  301.                     break;
  302.                     default: 
  303.                     break;
  304.                         } /* switch FindWindow */
  305.                 break;
  306.                 case keyDown:
  307.                 case autoKey:
  308.                     
  309.                 break;
  310.                 case updateEvt:
  311.                     
  312.                 break;
  313.                 case diskEvt:
  314.                     if (HiWord(gEvtDetails.event.message) != noErr)
  315.                         {
  316.                         DILoad();
  317.                         where.h = where.v = 85;
  318.                         DIBadMount(where, gEvtDetails.event.message);
  319.                         }
  320.                 break;
  321.                 case activateEvt:
  322.                     
  323.                 break;
  324.                 case kOSEvent:
  325.                     switch((gEvtDetails.event.message >> 24) & 0xff)
  326.                         {
  327.                     case mouseMovedMessage:
  328.                         BlinkTextCursor();
  329.                     break;
  330.                     case suspendResumeMessage:
  331.                         /* NOT HERE if modeless in front */
  332.                         gInBackground = ((gEvtDetails.event.message & resumeFlag) == 0);
  333.                         /****** Remove notice if hAWK finished while Minimal App was
  334.                         in the background. */
  335.                         if (gNotifying)
  336.                             {
  337.                             NMRemove(&gNotifyRec);
  338.                             if (gNotifyRec.nmIcon)
  339.                                 ReleaseResource(gNotifyRec.nmIcon);
  340.                             gNotifying = FALSE;
  341.                             /* ShowResultsAfterNotify(); -not implemented */
  342.                             }
  343.                     break;
  344.                         } /* switch message */
  345.                 break;
  346.                 case kHighLevelEvent:
  347.                     AEProcessAppleEvent(&gEvtDetails.event);
  348.                 break;
  349.                     } /* switch what */
  350.                 } /* not modeless dialog */
  351.             } /* if got event */
  352.         else
  353.             BlinkTextCursor();
  354.         AdjustCursor(gEvtDetails.event.where, cursorRgn);
  355.         } while (!gQuitting);
  356.     } /* end main() */
  357.  
  358. /* Very routine stuff, though note the stack is enlarged - hAWK needs
  359. a lot of stack. */
  360. void        DoStandardInits()
  361.     {
  362.     short    i;
  363.     EventRecord    event;
  364.     
  365.     /********************* Adjust stack
  366.     - note long StackSpace() returns current room left on stack
  367.     at any time, if there is future trouble...*/
  368.     SetApplLimit(GetApplLimit() - 57344);
  369.     MaxApplZone();
  370.     for (i = 0; i < 18; ++i)
  371.         MoreMasters();
  372.     InitGraf(&qd.thePort);
  373.     InitFonts();
  374.     FlushEvents(everyEvent, 0);
  375.     InitWindows();
  376.     InitMenus();
  377.     TEInit();
  378.     InitDialogs(0L);
  379.     InitCursor();
  380.     for (i = 0; i < 3; ++i)
  381.         EventAvail(everyEvent, &event);
  382.     }/* end DoStandardInits() */
  383.  
  384. void        MakeMenus()
  385.     {
  386.  
  387.     appleMenu = NewMenu(APPLEID,(StringPtr)"\p\24");    
  388.     AppendMenu(appleMenu,(StringPtr)"\p(About nothing...;(-");
  389.     AddResMenu(appleMenu,'DRVR');
  390.     InsertMenu(appleMenu,0);
  391.  
  392.     fileMenu = NewMenu(FILEID,(StringPtr)"\pFile");
  393.     AppendMenu(fileMenu,(StringPtr)"\pNew;Open...;(-;Close;Save;Save as...;Revert;(-;Page Setup...;Print...;(-;Quit/Q");
  394.     InsertMenu(fileMenu,0);    
  395.  
  396.     editMenu = NewMenu(EDITID,(StringPtr)"\pEdit");
  397.     AppendMenu(editMenu,(StringPtr)"\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear");
  398.     InsertMenu(editMenu,0);
  399.  
  400.     DrawMenuBar();
  401.  
  402.     } /* end MakeMenus() */
  403.  
  404. /* DoMenu returns TRUE when quit selected. If hAWK is running, we force it
  405. to quit also with a command-period. */
  406. Boolean        DoMenu(menuAndItem)
  407. long        menuAndItem;
  408.     {
  409.     short    theItem;
  410.     char    name[64];
  411.     
  412.     theItem = LoWord(menuAndItem);
  413.     switch (HiWord(menuAndItem))
  414.         {
  415.     case APPLEID:
  416.         if (theItem > 1)
  417.             {
  418.             GetItem(appleMenu, theItem, (StringPtr)name);
  419.             OpenDeskAcc((StringPtr)name);
  420.             }
  421.     break;
  422.     case FILEID:
  423.         if (theItem == QUIT)
  424.             {
  425.             /*********** Request stop Drag_on with <Command><period> first. */
  426.             TellHAWKtoQuit();
  427.             return(TRUE);
  428.             }
  429.     break;
  430.     case EDITID:
  431.         if (theItem <= 6 && SystemEdit (theItem - 1))
  432.             return(FALSE);
  433.         /***************** Calling all Drag_ons */
  434.         if (theItem > 6)
  435.             {
  436.             CallResource( EDITID, theItem,
  437.                          !gEvtDetails.shiftDown && !gEvtDetails.optionDown,
  438.                          NULL);
  439.             }
  440.     break;
  441.     default:
  442.     break;
  443.         }
  444.     HiliteMenu(0);
  445.     return(FALSE);
  446.     } /* end DoMenu() */
  447.  
  448. /* ------------ Apple event handlers --------------- */
  449. /* */
  450. pascal OSErr Handle_aevt_oapp(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon)
  451.     {
  452.     OSErr    theErr = noErr;
  453.     
  454.     theErr = MissedAEKeyword(theAppleEvent);
  455.     if (theErr) return theErr;
  456.     /* A larger app might open something here;*/
  457.     return theErr;
  458.     }
  459.  
  460. /* Minimal App7 doesn't open documents, but it might some day... */
  461. pascal OSErr Handle_aevt_odoc(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon)
  462.     {
  463.     AEDesc        theAEDesc;
  464.     AEKeyword    theAEKeyword;
  465.     FSSpec        theSpec;
  466.     DescType    typeCode;
  467.     FInfo        fndrInfo;
  468.     OSErr        theErr;
  469.     Size        actualSize;
  470.     long        i, count;
  471.     Boolean        stationery;
  472.     
  473.     theErr = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &theAEDesc);
  474.     if (theErr) return theErr;
  475.     theErr = MissedAEKeyword(theAppleEvent);
  476.     if (theErr) return theErr;
  477.     theErr = AECountItems(&theAEDesc, &count);
  478.     if (theErr) return theErr;
  479.     for (i = 1; i <= count; ++i)
  480.         {
  481.         theErr = AEGetNthPtr(&theAEDesc, i, typeFSS, &theAEKeyword, &typeCode,
  482.                     (Ptr)&theSpec, sizeof(FSSpec), &actualSize);
  483.         if (theErr) return theErr;
  484.         /* - minimal app doesn't know how to open windows.
  485.         theErr = FSpGetFInfo(&theSpec, &fndrInfo);
  486.         stationery = ((fndrInfo.fdFlags & 0x0800) != 0);
  487.         DoNewWindow(&theSpec, stationery);
  488.         */
  489.         }
  490.     return noErr;
  491.     }
  492.  
  493. /* */
  494. pascal OSErr Handle_aevt_pdoc(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon)
  495.     {
  496.     return errAEEventNotHandled;
  497.     }
  498.  
  499. /* */
  500. pascal OSErr Handle_aevt_quit(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon)
  501.     {
  502.     OSErr    theErr;
  503.     
  504.     theErr = MissedAEKeyword(theAppleEvent);
  505.     if (theErr) return theErr;
  506.     
  507.     TellHAWKtoQuit();
  508.     gQuitting = TRUE;
  509.     return noErr;
  510.     }
  511.  
  512. /* The logic here may seem reversed, but the goal is to check if
  513. anything was missed. "NotFound" means the search for something missed
  514. turned up nothing, so all was well.
  515. */
  516. OSErr MissedAEKeyword(AppleEvent *theAppleEvent)
  517.     {
  518.     OSErr        theErr;
  519.     DescType    typeCode;
  520.     Size        actualSize;
  521.     
  522.     theErr = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr,
  523.                 typeWildCard, &typeCode, NULL, 0, &actualSize);
  524.     if (theErr == errAEDescNotFound)
  525.         return noErr;
  526.     if (theErr == noErr)
  527.         return errAEEventNotHandled;
  528.     return theErr;
  529.     }
  530.  
  531. /* ---------- some WNE functions --------- */
  532. void HandleModelessDialog()
  533.     {
  534.     ;
  535.     }
  536.  
  537. void SetEventDetails()
  538.     {
  539.     static unsigned long     oldTime = 0L;
  540.     static Point            globalWhere = {-1000, -1000};
  541.     unsigned long            newTime;
  542.     short                dH, dV;
  543.     Point            newWhere;
  544.     
  545.     if (gEvtDetails.event.what == mouseDown || gEvtDetails.event.what == keyDown
  546.         || gEvtDetails.event.what == kOSEvent)
  547.         {
  548.         gEvtDetails.shiftDown = (gEvtDetails.event.modifiers & shiftKey) != 0;
  549.         gEvtDetails.capsLockDown = (gEvtDetails.event.modifiers & alphaLock) != 0;
  550.         gEvtDetails.optionDown = (gEvtDetails.event.modifiers & optionKey) != 0;
  551.         gEvtDetails.commandDown = (gEvtDetails.event.modifiers & cmdKey) != 0;
  552.         }
  553.     if (gEvtDetails.event.what == mouseDown)
  554.         {
  555.         Delay(0L, (long *)&newTime);
  556.         newWhere = gEvtDetails.event.where;
  557.         dH = newWhere.h - globalWhere.h;
  558.         dV = newWhere.v - globalWhere.v;
  559.         if (dH < 0)
  560.             dH = -dH;
  561.         if (dV < 0)
  562.             dV = -dV;
  563.         if ((newTime - oldTime) <= GetDblTime()
  564.             && dH <= 5 && dV <= 5)
  565.             gEvtDetails.doubleClick = TRUE;
  566.         else
  567.             gEvtDetails.doubleClick = FALSE;
  568.         globalWhere = newWhere;
  569.         GlobalToLocal (&newWhere);
  570.         gEvtDetails.localWhere = newWhere;
  571.         oldTime = newTime;
  572.         }
  573.     else
  574.         gEvtDetails.doubleClick = FALSE;
  575.     }
  576.  
  577.  
  578. unsigned long GetSleep()
  579.     {
  580.     long        sleep;
  581.     
  582.     /******** Less sleeping if hAWK is running - adjust if you like. */
  583.     if (gHawkIsRunning)
  584.         return(2UL);
  585.     sleep = GetCaretTime();
  586.     return((unsigned long)sleep);
  587.     }
  588.  
  589.  
  590. /*
  591.  * BlinkTextCursor - flash cursor
  592.  */
  593. void BlinkTextCursor()
  594.     {
  595.     WindowDataPtr wdPtr;
  596.     DialogPtr    dP;
  597.     short            item;
  598.     
  599.     /* we only adjust the cursor when we are in front */
  600.     if (gInBackground)
  601.         return;
  602.     wdPtr = (WindowDataPtr) FrontWindow();
  603.     /* Your idle procedure here */
  604.     }
  605.  
  606. /* More than needed here, you can build on this for your own
  607. cursor management. */
  608. void AdjustCursor(Point mouse, RgnHandle region)
  609.     {
  610.     WindowDataPtr wdPtr;
  611.     Rect        iBeamRect;
  612.  
  613.     wdPtr = (WindowDataPtr) FrontWindow(); /* Adjust the cursor only when we are in front */
  614.     if (!gInBackground && !daInFront)
  615.         {
  616.         /* calculate regions for different cursor shapes */
  617.         SetRectRgn(iBeamRgn, 0,0,0,0);
  618.         /* start arrowRgn wide open */
  619.         SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  620.  
  621.         /* calculate iBeamRgn */
  622.         if (IsMultiCursorWindow(wdPtr))
  623.             {
  624.             /* GetYourTextRect(wdPtr, &iBeamRect); - not implemented,
  625.             should replace next line. */
  626.             iBeamRect = ((WindowPeek)wdPtr)->port.portRect;
  627.             RectRgn(iBeamRgn, &iBeamRect);
  628.             SectRgn(iBeamRgn, ((WindowPtr)wdPtr)->visRgn, iBeamRgn);
  629.             /* make a global version of the iBeamRgn */
  630.             OffsetRgn(iBeamRgn,-((WindowPtr)wdPtr)->portBits.bounds.left,
  631.                     -((WindowPtr)wdPtr)->portBits.bounds.top);
  632.             }
  633.  
  634.         /* subtract other regions from arrowRgn */
  635.         DiffRgn(arrowRgn, iBeamRgn, arrowRgn);
  636.  
  637.         /* change the cursor and the region parameter */
  638.         if (PtInRgn(mouse, iBeamRgn) )
  639.             {
  640.             SetCursor(*IBeam);
  641.             CopyRgn(iBeamRgn, region);
  642.             }
  643.         else
  644.             {
  645.             InitCursor();
  646.             CopyRgn(arrowRgn, region);
  647.             }
  648.         }
  649.     }
  650.  
  651. Boolean    IsMultiCursorWindow(WindowDataPtr wdPtr)
  652.     {
  653.     return(FALSE);
  654.     }
  655.  
  656. /* SetWatchCursor - change cursor to watch, if available
  657. */
  658. void SetWatchCursor()
  659.     {
  660.     if (Watch)
  661.         SetCursor (*Watch);
  662.     else
  663.         InitCursor();
  664.     }
  665.  
  666. /* ---------------- support functions -------------- */
  667.  
  668. #ifndef _GestaltDispatch
  669. #define _GestaltDispatch                0xA0AD
  670. #endif
  671.  
  672. /* */
  673. Boolean System7Available()
  674.     {
  675.     long    sysVersion;
  676.     
  677.     if (!TrapAvailable(_GestaltDispatch))
  678.         return FALSE;
  679.     if (!Gestalt(gestaltSystemVersion,&sysVersion))
  680.         {
  681.         if (sysVersion >= 0x700)
  682.             return TRUE;
  683.         }
  684.     return FALSE;
  685.     }
  686.  
  687. /* */
  688. Boolean TrapAvailable(short theTrap)
  689.     {
  690.     TrapType        tType;
  691.     
  692.     tType = GetTrapType(theTrap);
  693.     if (tType == ToolTrap)
  694.         {
  695.         theTrap = (theTrap & 0x07FF);
  696.         if (theTrap >= NumToolboxTraps())
  697.             theTrap = _Unimplemented;
  698.         }
  699.     return(NGetTrapAddress(theTrap, tType) != NGetTrapAddress(_Unimplemented, ToolTrap));
  700.     }
  701.  
  702. /* */
  703. TrapType GetTrapType(short theTrap)
  704.     {
  705.     if ((theTrap & 0x0800) > 0)
  706.         return ToolTrap;
  707.     return OSTrap;
  708.     }
  709.  
  710. /* */
  711. short NumToolboxTraps()
  712.     {
  713.     if (NGetTrapAddress(_InitGraf, ToolTrap)
  714.         == NGetTrapAddress(0xAA6E, ToolTrap))
  715.         return 0x0200;
  716.     return 0x0400;
  717.     }
  718.  
  719. void AEInstallEventHandlers()
  720.     {
  721.     AEEventHandlerUPP aHandler;
  722.     
  723.     aHandler = NewAEEventHandlerProc(Handle_aevt_oapp);
  724.     AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
  725.         aHandler, 0L, FALSE);
  726.     aHandler = NewAEEventHandlerProc(Handle_aevt_odoc);
  727.     AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
  728.         aHandler, 0L, FALSE);
  729.     aHandler = NewAEEventHandlerProc(Handle_aevt_pdoc);
  730.     AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
  731.         aHandler, 0L, FALSE);
  732.     aHandler = NewAEEventHandlerProc(Handle_aevt_quit);
  733.     AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
  734.         aHandler, 0L, FALSE);
  735.     }
  736.  
  737. void SeeIfDAIsFrontWindow()
  738.     {
  739.     WindowPeek    wP = (WindowPeek)FrontWindow();
  740.     
  741.     if (wP && (wP->windowKind < 0))
  742.         daInFront = TRUE;
  743.     else if (daInFront)
  744.         {
  745.         daInFront = FALSE;
  746.         /*ConvertScrapIfChanged(); - not implemented */
  747.         }
  748.     }
  749.  
  750. /********* For running Drag_on's concurrently, the calling application
  751. (here Minimal App) handles all the events while the Drag_on chugs away.
  752. Note that quitting this app with a Quit from the menu or an AEvent
  753. forces the hAWK program to terminate.
  754. */
  755. void HandleOneEvent()
  756.     {
  757.     Point        where;
  758.     Boolean        gotEvent;
  759.     short        part;
  760.     
  761.     /* regular polling goes here */
  762.     SeeIfDAIsFrontWindow();
  763.     if (gInBackground)
  764.         {
  765.         /* handle being in the background */
  766.         ;
  767.         }
  768.     
  769.     gotEvent = WaitNextEvent(everyEvent, &gEvtDetails.event, GetSleep(), cursorRgn);
  770.     if (gotEvent)
  771.         {
  772.         SetEventDetails();
  773.  
  774.         AdjustCursor(gEvtDetails.event.where, cursorRgn);
  775.         
  776.         if (IsDialogEvent(&gEvtDetails.event))
  777.             HandleModelessDialog();
  778.         else
  779.             {
  780.             switch (gEvtDetails.event.what)
  781.                 {
  782.             case mouseDown:
  783.                 switch (part = FindWindow(gEvtDetails.event.where,
  784.                                 &gEvtDetails.mouseDownWindow)) 
  785.                     {
  786.                 case inDesk: 
  787.                     SysBeep(2);
  788.                 break;
  789.                 case inMenuBar:
  790.                     // If we go, hAWK goes too.
  791.                     gQuitting = DoMenu(MenuSelect(gEvtDetails.event.where));
  792.                 case inSysWindow:
  793.                     SystemClick(&gEvtDetails.event, gEvtDetails.mouseDownWindow);
  794.                 break;
  795.                 case inDrag:
  796.                 break;
  797.                 case inZoomIn:
  798.                 case inZoomOut:
  799.                 break;
  800.                 case inGrow:
  801.                 break;
  802.                 case inGoAway:
  803.                 break;
  804.                 case inContent:
  805.                 break;
  806.                 default: 
  807.                 break;
  808.                     } /* switch FindWindow */
  809.             break;
  810.             case keyDown:
  811.             case autoKey:
  812.                 
  813.             break;
  814.             case updateEvt:
  815.                 
  816.             break;
  817.             case diskEvt:
  818.                 if (HiWord(gEvtDetails.event.message) != noErr)
  819.                     {
  820.                     DILoad();
  821.                     where.h = where.v = 85;
  822.                     DIBadMount(where, gEvtDetails.event.message);
  823.                     }
  824.             break;
  825.             case activateEvt:
  826.                 
  827.             break;
  828.             case kOSEvent:
  829.                 switch((gEvtDetails.event.message >> 24) & 0xff)
  830.                     {
  831.                 case mouseMovedMessage:
  832.                     BlinkTextCursor();
  833.                 break;
  834.                 case suspendResumeMessage:
  835.                     gInBackground = (gEvtDetails.event.message & resumeFlag) == 0;
  836.                 break;
  837.                     }
  838.             break;
  839.             case kHighLevelEvent:
  840.                 AEProcessAppleEvent(&gEvtDetails.event);
  841.             break;
  842.                 } /* switch */
  843.             } /* not modeless dialog */
  844.         } /* if got event */
  845.     else
  846.         BlinkTextCursor();
  847.     AdjustCursor(gEvtDetails.event.where, cursorRgn);
  848.     }
  849.  
  850. /* Run hAWK program at startup if there is a command line on the clipboard.
  851. */
  852. Boolean FireOffHawkProgram(void)
  853.     {
  854.     MenuHandle         menu;
  855.     Str255            name;
  856.     short            numItems;
  857.     short            i;
  858.     Boolean            result = FALSE;
  859.     
  860.     // Is hAWK available?
  861.     menu = GetMHandle(EDITID);
  862.     if (menu != NULL)
  863.         {
  864.         numItems = CountMItems(menu);
  865.         for (i = 7; i <= numItems; ++i)
  866.             {
  867.             GetItem(menu, i, name);
  868.             if ( name[0] == 4
  869.               && name[1] == 'h'
  870.               && name[2] == 'A'
  871.               && name[3] == 'W'
  872.               && name[4] == 'K' )
  873.                 {
  874.                 Ptr        commandLineP;
  875.                 
  876.                 commandLineP = GetCommandLineFromScrap();
  877.                 if (commandLineP != NULL)
  878.                     {
  879.                     KeyMap        k;
  880.                     Boolean        shiftIsDown;
  881.                     Boolean        optionIsDown;
  882.                     
  883.                     GetKeys(k);
  884.                     if (BitTst(&(k[0]), 61))
  885.                         optionIsDown = TRUE;
  886.                     if (BitTst(&(k[0]), 63))
  887.                         shiftIsDown = TRUE;
  888.                     CallResource( EDITID,
  889.                                   i,
  890.                                   !shiftIsDown && !optionIsDown,
  891.                                   commandLineP );
  892.                     DisposePtr(commandLineP);
  893.                     result = TRUE;
  894.                     }
  895.                 break;
  896.                 }
  897.             }
  898.         }
  899.     return result;
  900.     }
  901.  
  902. /* Get command line for hAWK from scrap as C string, or return NULL.
  903. */
  904. char *GetCommandLineFromScrap(void)
  905.     {
  906.     Handle            scrapTextH;            // copy of scrap text
  907.     char            name[16];            // for GenericGetName
  908.     short            nameLength;            // ditto
  909.     long            offset;                // into scrap
  910.     long            numChars = 0;        // num text chars on scrap
  911.     long            onScrap;
  912.     Ptr                bPtr,                // start of text
  913.                     cPtr,                // advances through the text
  914.                     topPtr;             // end of text
  915.     Ptr                commandLineP = NULL;// allocated cmd line or NULL
  916.     ScrapStuff         *scrapStuff;
  917.     
  918.     scrapStuff = InfoScrap();
  919.     
  920.     scrapTextH = NewHandle(0);
  921.     if (scrapTextH != NULL)
  922.         {
  923.         numChars = GetScrap(scrapTextH,'TEXT',&offset);
  924.         if (numChars > 7) // "hAWK -fX" is smallest command line, 8 chars
  925.             {
  926.             bPtr = *scrapTextH;
  927.             cPtr = bPtr;
  928.             topPtr = bPtr + numChars;
  929.             while (*cPtr == BLANK || (*cPtr > 0 && *cPtr <= CR)
  930.                 || *cPtr == OPTBL)
  931.                 ++cPtr;
  932.             nameLength = 15;
  933.             if ( GenericGetName(&cPtr, topPtr, name, &nameLength)
  934.               && nameLength == 4 )
  935.                 {
  936.                 if ( (*name == 'h'        || *name == 'H')
  937.                   && (*(name+1) == 'a' || *(name+1) == 'A')
  938.                   && (*(name+2) == 'w' || *(name+2) == 'W')
  939.                   && (*(name+3) == 'k' || *(name+3) == 'K') )
  940.                     {
  941.                     commandLineP = NewPtr(numChars + 1);
  942.                     if (commandLineP != NULL)
  943.                         {
  944.                         // Fill in the new ptr.
  945.                         BlockMove(*scrapTextH, commandLineP, numChars);
  946.                         commandLineP[numChars] = '\0';
  947.                         }
  948.                     }
  949.                 }
  950.             }
  951.         // else scrap very short or error getting scrap text
  952.         DisposeHandle(scrapTextH);
  953.         }
  954.     return commandLineP;
  955.     }
  956.  
  957. // If at a name, load it to patPtr, get length, adjust posPtr past it.
  958. Boolean GenericGetName(Ptr *posPtrPtr, Ptr eofPtr, Ptr patPtr, short *patLenP)
  959.     {
  960.     Ptr            cPtr = *posPtrPtr;
  961.     short        nameLen;
  962.     short        maximumLength = *patLenP;
  963.     
  964.     if (maximumLength <= 0)
  965.         maximumLength = 127;
  966.     if (cPtr >= eofPtr)
  967.         return(FALSE);
  968.     if (alpha(*cPtr))
  969.         {
  970.         nameLen = 1;
  971.         *patPtr++ = *cPtr++;
  972.         while (alphanum(*cPtr) && cPtr < eofPtr && nameLen < maximumLength)
  973.             {
  974.             ++nameLen;
  975.             *patPtr++ = *cPtr++;
  976.             }
  977.         *patLenP = nameLen;
  978.         *posPtrPtr = cPtr;
  979.         return(TRUE);
  980.         }
  981.     else
  982.         return(FALSE);
  983.     }
  984.  
  985. #define kPeriod 0x2f2e
  986. /* Send a command-period to hAWK
  987. */
  988. void TellHAWKtoQuit(void)
  989.     {
  990.     OSErr    theErr;
  991.     EvQEl    *qElPtr;
  992.     
  993.     if (!gHawkIsRunning)
  994.         return;
  995.     theErr = PPostEvent(keyDown,kPeriod,&qElPtr);
  996.     if (theErr == noErr)
  997.         qElPtr->evtQModifiers = cmdKey;
  998.     }
  999.